#ifndef IPLUGINCONTACTMODELV2_0_0
#define IPLUGINCONTACTMODELV2_0_0

/***************************************************************************/
/* This header file contains the V2.0.0 plugin contact model API           */
/* definition.  Include this header and PluginContactModelCore.h into      */
/* your plugin project then implement the methods from                     */
/* PluginContactModelCore.h and create a new class derived from            */
/* IPluginContactModelV2_0_0 that implements your desired functionality    */
/***************************************************************************/

#include "PluginConstants.h"
#include "IPluginContactModel.h"

namespace NApiCore
{
    class IApiManager_1_0;
};

namespace NApiCm
{
    /**
     * This interface contains all of the methods required to create a
     * contact model plugin.  A new class should be created that derives
     * from this interface and implements all of its methods. Additionally
     * the methods from the PluginContactModelCore.h file need to be implemented.
     *
     * NAME:              Contact Model Plugin API
     * VERSION:           2.0.0
     * CUSTOM PROPERTIES: Particle
     *
     * The methods required by the interface are:
     *
     * getPreferenceFileName(...)
     *     Returns the name of the config file used by this model (if any).
     *
     * isThreadSafe(...)
     *     Indicates that the plugin's calculateForce(...) method is thread
     *     safe (returns true) or not (returns false).  A thread safe
     *     calculateForce(...) can be called in parallel by threads running
     *     on multiple processors. This can speed up the simulation
     *     processing.
     *
     * usesCustomProperties(...)
     *     Indicates that the plugin wishes to register and/or receive custom
     *     particle property data.  Formatting the custom particle property
     *     data in a way that can be passed to plugins is expensive and should
     *     only be done if the data is actually required.
     *
     * setup(...)
     *     Performs any one-off setup and initialization just after the
     *     plugin is loaded.
     *
     * starting(...)
     *     Called just before simulation starts to allow API handles to
     *     be acquired, temporary storage allocated, files opened etc.
     *
     * stopping()
     *     Called just after simulation stops to allow API handles to
     *     be released, temporary storage freed, files closed etc.
     *
     * calculateForce(...)
     *     does the actual force calculation for a contact.
     *
     * registerNewParticleProperty(...)
     *     Called by EDEM to inform the plugin of a new finalized custom 
     *     particle property
     *
     * getNumberOfRequiredProperties(...)
     *     Called by EDEM to query the number of custom particle properties
     *     required by this plugin to run.
     *
     * getDetailsForProperty(...)
     *     Returns the details for the custom particle properties required
     *     for this plugin to run.
     *
     * If you need per plugin instance data simply add entries to your
     * plugin's class definition as you would with any other C++ class
     * definition.
     */
    class IPluginContactModelV2_0_0 : public IPluginContactModel
    {
        public:
            /**
             * Constructor, does nothing
             */
            IPluginContactModelV2_0_0() {}

            /**
             * Destructor, does nothing
             */
            virtual ~IPluginContactModelV2_0_0() {}

            /**
             * Retrieves the name of the config file used by the plugin.
             *
             * If the plugin does not need a config file then prefFileName
             * should be set to an empty string.
             *
             * @param prefFileName (RETURN VALUE)
             *                     A character array to be populated with the
             *                     config file name. This path is relative to
             *                     the directory the plugin is stored in.
             *                     EDEM will prepend the full directory the plugin
             *                     is stored in and pass it back to the setup method.
             */
            virtual void getPreferenceFileName(char prefFileName[NApi::FILE_PATH_MAX_LENGTH]) = 0;

            /**
             * If the plugin implementations calculateForce() method is thread
             * safe then this method should return true.
             *
             * When a plug-in is thread safe, EDEM allows multiple threads
             * to call the plug-in at the same time.  This can speed-up
             * calculations substantially on multi-processor machines.
             *
             * Thread safe programming requires a number of conventions and
             * restrictions to be followed.  If in doubt set this method to return
             * false.
             *
             * @return Bool to indicate if the calculateForce() method is thread
             *         safe
             */
            virtual bool isThreadSafe() = 0;

            /**
             * Indicates whether the plugin wishes to register or receive custom
             * particle property data.
             *
             * Formatting the custom particle property data for use in plugins
             * requires a number of memcpy operations that will slow down the
             * program if the data is not actually required.
             *
             * @return Bool to indicate if custom particle properties are to
             *         be registered or should be supplied to the
             *         calculateForce(...) method.
             */
            virtual bool usesCustomProperties() = 0;

            /**
             * Initializes the plugin by giving it a chance to read any config
             * files, open temporary files, generate data structures or any other
             * one-off setup work.
             *
             * This method is called once, shortly after the plugin is first loaded.
             * If this method returns false EDEM will immediately delete the plugin
             * and an error message will be reported.
             *
             * @param prefFile Full path to optional preferences file or empty
             *                 string if none
             * @return Bool to say if setup was a success
             */
            virtual bool setup(const char prefFile[]) = 0;

            /**
             * Called to indicate processing is about to begin and the
             * model should allocate any temporary storage and retrieve any
             * file/api/socket handles it may need.
             *
             * If the method returns false then processing will not start.
             *
             * IMPORTANT: Plugins should only retrieve API handles in this
             * method. API handles may change between one processing
             * run and another. Attempting to keep and re-use handles
             * will cause system instability.
             *
             * @param apiManager The api manager for use by plugin models
             * @return true if model is ready to start, else false
             */
            virtual bool starting(NApiCore::IApiManager_1_0& apiManager) = 0;

            /**
             * Called to indicate processing is finished and that
             * the model should free any temporary storage and close/release
             * file/api/socket handles.
             *
             * The implementation must be able to handle this method being
             * called multiple times in a row without intervening calls
             * to starting.  This can occur when one or more loaded models
             * abort processing.
             *
             * IMPORTANT: Plugins must release all API handles in this
             * method.  API handles may change between one processing
             * run and another.  Attempting to keep and re-use handles
             * will cause system instability.
             */
            virtual void stopping(NApiCore::IApiManager_1_0& apiManager) = 0;

            /**
             * This function is called when two elements are in contact with
             * each other.
             *
             * These elements can be two surfaces or a surface and a geometry
             * element.  For two surfaces, the function is called when their
             * contact radii cross.  For a surface and a geometry, the
             * function is called when the contact radius of the surface
             * touches the geometry.
             *
             * @param time
             *            Current time
             * @param timestep
             *            Length of timestep used in simulation
             * @param elem1IsSurf
             *            true if the element is a surface, false if not
             * @param elem1Id
             *            The id of the element
             * @param elem1Type
             *            Name of the particle template this surface was created
             *            from if elem1IsSurf is true or the name of the geometry
             *            section if elem1IsSurf is true
             * @param elem1Mass
             *            The mass of the parent particle if elem1IsSurf is true,
             *            otherwise a large number (usually 1e8) if elem1IsSurf
             *            is false.
             * @param elem1ShearMod
             *            The shear modulus of the element
             * @param elem1Poisson
             *            Poisson's ratio of the element
             * @param elem1ContactCurvature
             *            The local contact curvature of the element at the
             *            contact point
             * @param elem1PhysicalCurvature
             *            The local physical curvature of the element at the
             *            contact point
             * @param elem1PosX
             *            X coordinate of the centroid of the element (NOT
             *            necessarily the particle)
             * @param elem1PosY
             *            Y coordinate of the centroid of the element (NOT
             *            necessarily the particle)
             * @param elem1PosZ
             *            Z coordinate of the centroid of the element (NOT
             *            necessarily the particle)
             * @param elem1VelX
             *            X component of velocity the element at the contact point
             * @param elem1VelY
             *            Y component of velocity the element at the contact point
             * @param elem1VelZ
             *            Z component of velocity the element at the contact point
             * @param elem1AngVelX
             *            X component of angular velocity of the element
             * @param elem1AngVelY
             *            Y component of angular velocity of the element
             * @param elem1AngVelZ
             *            Z component of angular velocity of the element
             * @param elem1Charge
             *            Charge of the element
             * @param elem1WorkFunction
             *            Work function of the element
             * @param elem1Orientation
             *            Nine-element array containing the orientation matrix for
             *            this element.
             *            The elements of the array are in the following order:
             *                XX, XY, XZ, YX, YY, YZ, ZX, ZY, ZZ
             * @param elem1PropertyList
             *            Pointer to a double array containing the property list
             *            for the surface if elem1IsSurf is true, or 0 if
             *            elem1IsSurf is false
             * @param elem2IsSurf
             *            As elem1IsSurf but for element 2
             * @param elem2Id
             *            As elem1Id but for element 2
             * @param elem2Type
             *            As elem1Type but for element 2
             * @param elem2Mass
             *            As elem1Mass but for element 2
             * @param elem2ShearMod
             *            As elem1ShearMod but for element 2
             * @param elem2Poisson
             *            As elem1Poisson but for element 2
             * @param elem2ContactCurvature
             *            As elem1ContactCurvature but for element 2
             * @param elem2PhysicalCurvature
             *            As elem1PhysicalCurvature but for element 2
             * @param elem2PosX
             *            As elem1PosX but for element 2
             * @param elem2PosY
             *            As elem1PosY but for element 2
             * @param elem2PosZ
             *            As elem1PosZ but for element 2
             * @param elem2VelX
             *            As elem1VelX but for element 2
             * @param elem2VelY
             *            As elem1VelY but for element 2
             * @param elem2VelZ
             *            As elem1VelZ but for element 2
             * @param elem2AngVelX
             *            As elem1AngVelX but for element 2
             * @param elem2AngVelY
             *            As elem1AngVelY but for element 2
             * @param elem2AngVelZ
             *            As elem1AngVelZ but for element 2
             * @param elem2Charge
             *            As elem1Charge but for element 2
             * @param elem2WorkFunction
             *            As elem1WorkFunction but for element 2
             * @param elem2Orientation
             *            As elem1Orientation but for element 2
             * @param elem2PropertyList
             *            As elem1PropertyList but for element 2
             * @param coeffRest
             *            Coefficient of restitution
             * @param staticFriction
             *            Coefficient of static friction
             * @param rollingFriction
             *            Coefficient of rolling friction
             * @param contactPointX
             *            X coordinate of the location of the centroid of the contact
             * @param contactPointY
             *            Y coordinate of the location of the centroid of the contact
             * @param contactPointZ
             *            Z coordinate of the location of the centroid of the contact
             * @param normalOverlap
             *            Magnitude of the normal contact overlap
             * @param tangentialOverlapX
             *            (INPUT AND RETURN VALUE)
             *            X component of the tangential contact overlap.
             *            The contact model is allowed to change the value of the tangential contact overlap
             * @param tangentialOverlapY
             *            (INPUT AND RETURN VALUE)
             *            Y component of the tangential contact overlap.
             *            The contact model is allowed to change the value of the tangential contact overlap
             * @param tangentialOverlapZ
             *            (INPUT AND RETURN VALUE)
             *            Z component of the tangential contact overlap.
             *            The contact model is allowed to change the value of the tangential contact overlap
             * @param calculatedNormalForceX
             *            (RETURN VALUE)
             *            X component of normal force on element 1
             *            From Newton III the normal force on element 2 is equal and opposite.
             * @param calculatedNormalForceY
             *            (RETURN VALUE)
             *            Y component of normal force on element 1
             *            From Newton III the normal force on element 2 is equal and opposite.
             * @param calculatedNormalForceZ
             *            (RETURN VALUE)
             *            Z component of normal force on element 1
             *            From Newton III the normal force on element 2 is equal and opposite.
             * @param calculatedUnsymNormalForceX
             *            (RETURN VALUE)
             *            X component of the unsymmetrical normal forces on
             *            element 1. This represent the portion of the calculated
             *            normal force that causes energy loss / gain (eg damping).
             * @param calculatedUnsymNormalForceY
             *            (RETURN VALUE)
             *            Y component of the unsymmetrical normal forces on
             *            element 1. This represent the portion of the calculated
             *            normal force that causes energy loss / gain (eg damping).
             * @param calculatedUnsymNormalForceZ
             *            (RETURN VALUE)
             *            Z component of the unsymmetrical normal forces on
             *            element 1. This represent the portion of the calculated
             *            normal force that causes energy loss / gain (eg damping).
             * @param calculatedTangentialForceX
             *            (RETURN VALUE)
             *            X component of tangential force on element 1
             *            From Newton III the normal force on element 2 is equal and opposite.
             * @param calculatedTangentialForceY
             *            (RETURN VALUE)
             *            Y component of tangential force on element 1
             *            From Newton III the normal force on element 2 is equal and opposite.
             * @param calculatedTangentialForceZ
             *            (RETURN VALUE)
             *            Z component of tangential force on element 1
             *            From Newton III the normal force on element 2 is equal and opposite.
             * @param calculatedUnsymTangentialForceX
             *            (RETURN VALUE)
             *            X component of the unsymmetrical tangential forces on
             *            element 1. This represent the portion of
             *            calculatedTangentialForceX that causes energy
             *            loss / gain (eg damping).
             * @param calculatedUnsymTangentialForceY
             *            (RETURN VALUE)
             *            Y component of the unsymmetrical tangential forces on
             *            element 1. This represent the portion of
             *            calculatedTangentialForceY that causes energy
             *            loss / gain (eg damping).
             * @param calculatedUnsymTangentialForceZ
             *            (RETURN VALUE)
             *            Z component of the unsymmetrical tangential forces on
             *            element 1. This represent the portion of
             *            calculatedTangentialForceZ that causes energy
             *            loss / gain (eg damping).
             * @param calculatedElem1AdditionalTorqueX
             *            (RETURN VALUE)
             *            X coordinate of any additional torque on element 1 not
             *            accounted  for by the above forces (which are deemed to
             *            act at the contact point). These can be useful, for of
             *            example, in a consideration rolling friction.
             * @param calculatedElem1AdditionalTorqueY
             *            (RETURN VALUE)
             *            Y coordinate of any additional torque on element 1 not
             *            accounted  for by the above forces (which are deemed to
             *            act at the contact point). These can be useful, for of
             *            example, in a consideration rolling friction.
             * @param calculatedElem1AdditionalTorqueZ
             *            (RETURN VALUE)
             *            Z coordinate of any additional torque on element 1 not
             *            accounted  for by the above forces (which are deemed to
             *            act at the contact point). These can be useful, for of
             *            example, in a consideration rolling friction.
             * @param calculatedElem1UnsymAdditionalTorqueX
             *            (RETURN VALUE)
             *            X coordinate of any unsymmetrical, additional torque
             *            on element 1 not accounted for by the above forces.
             *            These represent the component of the additional torque
             *            that causes energy loss / gain (eg damping).
             * @param calculatedElem1UnsymAdditionalTorqueY
             *            (RETURN VALUE)
             *            Y coordinate of any unsymmetrical, additional torque
             *            on element 1 not accounted for by the above forces.
             *            These represent the component of the additional torque
             *            that causes energy loss / gain (eg damping).
             * @param calculatedElem1UnsymAdditionalTorqueZ
             *            (RETURN VALUE)
             *            Z coordinate of any unsymmetrical, additional torque
             *            on element 1 not accounted for by the above forces.
             *            These represent the component of the additional torque
             *            that causes energy loss / gain (eg damping).
             * @param calculatedElem1PropertyListChanges
             *            (RETURN VALUE)
             *            Array of double values the same length as the
             *            corresponding propertyList populated with deltas to the
             *            values where needed.  Unlike other parameters
             *            calculatedElem1PropertyListChanges may already
             *            contain data from prior contacts.
             *            Do not set these arrays to 0 and add or
             *            subtract your changes from the existing values
             * @param calculatedElem2AdditionalTorqueX
             *            (RETURN VALUE)
             *            X coordinate of any additional torque on element 2 not
             *            accounted  for by the above forces (which are deemed to
             *            act at the contact point). These can be useful, for of
             *            example, in a consideration rolling friction.
             * @param calculatedElem2AdditionalTorqueY
             *            (RETURN VALUE)
             *            Y coordinate of any additional torque on element 2 not
             *            accounted  for by the above forces (which are deemed to
             *            act at the contact point). These can be useful, for of
             *            example, in a consideration rolling friction.
             * @param calculatedElem2AdditionalTorqueZ
             *            (RETURN VALUE)
             *            Z coordinate of any additional torque on element 2 not
             *            accounted  for by the above forces (which are deemed to
             *            act at the contact point). These can be useful, for of
             *            example, in a consideration rolling friction.
             * @param calculatedElem2UnsymAdditionalTorqueX
             *            (RETURN VALUE)
             *            X coordinate of any unsymmetrical, additional torque
             *            on element 2 not accounted for by the above forces.
             *            These represent the component of the additional torque
             *            that causes energy loss / gain (eg damping).
             * @param calculatedElem2UnsymAdditionalTorqueY
             *            (RETURN VALUE)
             *            Y coordinate of any unsymmetrical, additional torque
             *            on element 2 not accounted for by the above forces.
             *            These represent the component of the additional torque
             *            that causes energy loss / gain (eg damping).
             * @param calculatedElem2UnsymAdditionalTorqueZ
             *            (RETURN VALUE)
             *            Z coordinate of any unsymmetrical, additional torque
             *            on element 2 not accounted for by the above forces.
             *            These represent the component of the additional torque
             *            that causes energy loss / gain (eg damping).
             * @param calculatedElem2PropertyListChanges
             *            (RETURN VALUE)
             *            Array of double values the same length as the
             *            corresponding propertyList populated with deltas to the
             *            values where needed.  Unlike other parameters
             *            calculatedElem2PropertyListChanges may already
             *            contain data from prior contacts.
             *            Do not set these arrays to 0 and add or
             *            subtract your changes from the existing values
             * @param calculatedChargeMovedToElem1
             *            (RETURN VALUE)
             *            The amount of charge moved from element 2 to element 1
             *            (if negative charge moves from element 1 to 2
             * @return enum value to indicate function result
             */
            virtual NApi::ECalculateResult calculateForce(
                                               double        time,
                                               double        timestep,
                                               bool          elem1IsSurf,
                                               int           elem1Id,
                                               const char    elem1Type[],
                                               double        elem1Mass,
                                               double        elem1ShearMod,
                                               double        elem1Poisson,
                                               double        elem1ContactCurvature,
                                               double        elem1PhysicalCurvature,
                                               double        elem1PosX,
                                               double        elem1PosY,
                                               double        elem1PosZ,
                                               double        elem1VelX,
                                               double        elem1VelY,
                                               double        elem1VelZ,
                                               double        elem1AngVelX,
                                               double        elem1AngVelY,
                                               double        elem1AngVelZ,
                                               double        elem1Charge,
                                               double        elem1WorkFunction,
                                               const double  elem1Orientation[9],
                                               const double* elem1PropertyList,
                                               bool          elem2IsSurf,
                                               int           elem2Id,
                                               const char    elem2Type[],
                                               double        elem2Mass,
                                               double        elem2ShearMod,
                                               double        elem2Poisson,
                                               double        elem2ContactCurvature,
                                               double        elem2PhysicalCurvature,
                                               double        elem2PosX,
                                               double        elem2PosY,
                                               double        elem2PosZ,
                                               double        elem2VelX,
                                               double        elem2VelY,
                                               double        elem2VelZ,
                                               double        elem2AngVelX,
                                               double        elem2AngVelY,
                                               double        elem2AngVelZ,
                                               double        elem2Charge,
                                               double        elem2WorkFunction,
                                               const double  elem2Orientation[9],
                                               const double* elem2PropertyList,
                                               double        coeffRest,
                                               double        staticFriction,
                                               double        rollingFriction,
                                               double        contactPointX,
                                               double        contactPointY,
                                               double        contactPointZ,
                                               double        normalOverlap,
                                               double&       tangentialOverlapX,
                                               double&       tangentialOverlapY,
                                               double&       tangentialOverlapZ,
                                               double&       calculatedNormalForceX,
                                               double&       calculatedNormalForceY,
                                               double&       calculatedNormalForceZ,
                                               double&       calculatedUnsymNormalForceX,
                                               double&       calculatedUnsymNormalForceY,
                                               double&       calculatedUnsymNormalForceZ,
                                               double&       calculatedTangentialForceX,
                                               double&       calculatedTangentialForceY,
                                               double&       calculatedTangentialForceZ,
                                               double&       calculatedUnsymTangentialForceX,
                                               double&       calculatedUnsymTangentialForceY,
                                               double&       calculatedUnsymTangentialForceZ,
                                               double&       calculatedElem1AdditionalTorqueX,
                                               double&       calculatedElem1AdditionalTorqueY,
                                               double&       calculatedElem1AdditionalTorqueZ,
                                               double&       calculatedElem1UnsymAdditionalTorqueX,
                                               double&       calculatedElem1UnsymAdditionalTorqueY,
                                               double&       calculatedElem1UnsymAdditionalTorqueZ,
                                               double*       calculatedElem1PropertyListChanges,
                                               double&       calculatedElem2AdditionalTorqueX,
                                               double&       calculatedElem2AdditionalTorqueY,
                                               double&       calculatedElem2AdditionalTorqueZ,
                                               double&       calculatedElem2UnsymAdditionalTorqueX,
                                               double&       calculatedElem2UnsymAdditionalTorqueY,
                                               double&       calculatedElem2UnsymAdditionalTorqueZ,
                                               double*       calculatedElem2PropertyListChanges,
                                               double&       calculatedChargeMovedToElem1) = 0;

            /**
             * Registers a new finalized particle property with the plugin.
             * As each custom particle property becomes finalised (available for
             * use) this method will be called with the details of the property.
             *
             * A plugin cannot use a particle property until it has been
             * registered with it via this method.  For details of how particle
             * properties are represented see the calculateForce method.
             *
             * If the plugin does not make use of custom particle properties this
             * method can be an empty stub that does nothing.
             *
             * @param name             The name of the property (null terminated
             *                         char array)
             * @param numberOfElements The number of elements in the property
             * @param dataType         The data type of the property, currently
             *                         allways eDouble
             * @param unitType         The unit type of the property
             * @param offset           The offset in a 1D property array to the first
             *                         element of the properties data.
             */
            virtual void registerNewParticleProperty(
                             const char*                          name,
                             const unsigned int                   numberOfElements,
                             const NApi::EPluginPropertyDataTypes dataType,
                             const NApi::EPluginPropertyUnitTypes unitType,
                             const unsigned int                   offset) = 0;

            /**
             * Returns the number of custom particle properties this plugin
             * wants to register with the system.
             *
             * If the plugin does not use custom particle properties this
             * method should return 0.
             *
             * @return The number of custom properties the plugin wishes to
             *         register.
             */
            virtual unsigned int getNumberOfRequiredProperties() = 0;

            /**
             * Retrieves details for a given particle property.  This method
             * will be called for propertyIndex values
             * 0...(getNumberOfRequiredProperties() - 1) to retrieve the details
             * for that particle property from the plugin.  These particle
             * properties will then be registered with the system if they do not
             * clash with any existing particle properties.
             *
             * To use a particle property, a plugin must first be passed the
             * offset of the property data to the registerNewParticleProperty()
             * method.
             *
             * If the plugin does not use custom particle properties this method
             * should always return false.
             *
             * @param propertyIndex    The index of the property to retrieve data
             *                         for
             * @param name             (RETURN VALUE)
             *                         A CUSTOM_PROP_MAX_NAME_LENGTH char array
             *                         is supplied to be populated with the name
             *                         of the property
             * @param dataType         (RETURN VALUE)
             *                         The data type of the property should allways
             *                         be set to eDouble
             * @param numberOfElements (RETURN VALUE)
             *                         The number of elements (min 1)
             * @param unitType         (RETURN VALUE)
             *                         The unit type of the property
             * @return bool to indicate whether data exists for the property
             */
            virtual bool getDetailsForProperty(
                             unsigned int                    propertyIndex,
                             char                            name[NApi::CUSTOM_PROP_MAX_NAME_LENGTH],
                             NApi::EPluginPropertyDataTypes& dataType,
                             unsigned int&                   numberOfElements,
                             NApi::EPluginPropertyUnitTypes& unitType) = 0;
    };
};

#endif // IPLUGINCONTACTMODELV2_0_0

